package com.kama.minispring.beans.factory.config;

import com.kama.minispring.beans.BeansException;
import com.kama.minispring.beans.factory.ConfigurableListableBeanFactory;

import java.util.Properties;

/**
 * BeanFactoryPostProcessor实现类，用于处理bean定义中的属性占位符
 * 例如将${jdbc.url}替换为properties文件中对应的值
 *
 * @author kama
 * @version 1.0.0
 */
public class PropertyPlaceholderBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    // 属性文件内容
    private Properties properties;
    // 属性前缀
    private String placeholderPrefix = "${";
    // 属性后缀
    private String placeholderSuffix = "}";

    /**
     * 设置属性文件内容
     *
     * @param properties 属性文件内容
     */
    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    /**
     * 设置属性前缀
     *
     * @param placeholderPrefix 属性前缀
     */
    public void setPlaceholderPrefix(String placeholderPrefix) {
        this.placeholderPrefix = placeholderPrefix;
    }

    /**
     * 设置属性后缀
     *
     * @param placeholderSuffix 属性后缀
     */
    public void setPlaceholderSuffix(String placeholderSuffix) {
        this.placeholderSuffix = placeholderSuffix;
    }

    /**
     * 在BeanFactory加载所有bean定义后，实例化任何bean之前处理bean定义
     *
     * @param beanFactory BeanFactory实例
     * @throws BeansException 处理属性占位符时可能抛出的异常
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            // 遍历所有bean定义
            String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
            for (String beanName : beanDefinitionNames) {
                // 获取当前bean的定义
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
                // 获取bean的属性值集合
                PropertyValues propertyValues = beanDefinition.getPropertyValues();

                // 遍历bean的所有属性
                for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                    // 获取属性值
                    Object value = propertyValue.getValue();
                    // 检查属性值是否为字符串类型
                    if (value instanceof String) {
                        // 将属性值转换为字符串
                        String stringValue = (String) value;
                        // 解析字符串中的占位符
                        String resolvedValue = resolvePlaceholder(stringValue);
                        // 如果解析后的值与原始值不同，则添加新的属性值
                        if (!stringValue.equals(resolvedValue)) {
                            propertyValues.addPropertyValue(
                                    new PropertyValue(propertyValue.getName(), resolvedValue));
                        }
                    }
                }
            }
        } catch (Exception e) {
            // 如果发生异常，抛出BeansException
            throw new BeansException("Error processing property placeholder", e);
        }

    }

    /**
     * 解析字符串中的属性占位符
     *
     * @param value 待解析的字符串
     * @return 解析后的字符串
     * @throws BeansException 解析属性占位符时可能抛出的异常
     */
    private String resolvePlaceholder(String value) throws BeansException {
        // 检查输入值是否为空或空字符串，如果为空，则直接返回原值
        if (value == null || value.length() == 0) {
            return value;
        }

        // 创建StringBuilder对象以提高字符串处理效率
        StringBuilder result = new StringBuilder(value);
        int startIdx;

        // 循环查找并替换所有占位符
        while ((startIdx = result.indexOf(placeholderPrefix)) != -1) {
            // 查找占位符的结束位置
            int endIdx = result.indexOf(placeholderSuffix, startIdx + placeholderPrefix.length());
            // 如果没有找到结束位置，则说明占位符格式错误，直接返回当前结果
            if (endIdx == -1) {
                return result.toString();
            }

            // 提取占位符中的变量名
            String placeholder = result.substring(startIdx + placeholderPrefix.length(), endIdx);
            // 通过变量名获取对应的值
            String resolvedValue = properties.getProperty(placeholder);

            // 如果没有找到对应的值，则抛出异常
            if (resolvedValue == null) {
                throw new BeansException("Could not resolve placeholder '" + placeholder + "'");
            }

            // 使用获取到的值替换原字符串中的占位符
            result.replace(startIdx, endIdx + placeholderSuffix.length(), resolvedValue);
        }

// 返回处理后的字符串
        return result.toString();

    }
}
